//
// Created by ChenYulu on 2017/6/4.
//

#include "bilateral.h"
/**
 *
 * @param src 原图
 * @param dst 效果图
 * @param size 滤波器大小
 * @param ss space sigma
 * @param rs range sigma
 * @return
 */
int Bilateral(Bitmap *src, Bitmap *dst, double ss, double rs) {
  int ret;
  int gray0 = 0, gray = 0, r0, g0, b0, r, g, b;
  int index0, index;
  int rowOffset, colOffset;
  static double factor = -0.5;
  int radius = (int) max(ss, rs);
  int size = 2 * radius + 1;
  double spaceWeightTable[size][size];//距离高斯权重表
  double rangeWeightTable[256];//灰度值高斯权重表
  double spaceCoeff = -0.5 / (ss * ss);
  double rangeCoeff = -0.5 / (rs * rs);
  double delta;
  double weight, sum = 0, wSum = 0;

  //创建目标图像
  if (src->bitCount == 8) {
    ret = CreateBitmap(dst, src->width, src->height, 8);
    if (ret == -1) {
      printf("Error(Bilateral filter): Can't create the image.\n");
      return -1;
    }
  }
//  else if (src->bitCount == 24) {
//    ret = CreateBitmap(dst, src->width, src->height, 24);
//    if (ret == -1) {
//      printf("Error(Bilateral filter): Can't create the image.\n");
//      return -1;
//    }
//  }
  else {
    printf("Error(Bilateral filter): Only support 8 or 24 bit BMP image.\n");
    return -1;
  }

  //建立距离高斯权重表
  for (int i = -radius; i <= radius; ++i) {
    for (int j = -radius; j <= radius; ++j) {
      //计算中心点和周围像素的欧几里得距离
      delta = sqrt(i * i + j * j) / ss;
      spaceWeightTable[i + radius][j + radius] = exp(delta * delta * factor);
    }
  }

  //建立灰度值高斯权重表
  for (int i = 0; i < 256; ++i) {
    delta = sqrt(i * i) / rs;
    rangeWeightTable[i] = exp(delta * delta * factor);
  }

  for (int i = 0; i < src->height; ++i) {
    if (src->bitCount == 8) {
      for (int j = 0; j < src->width; ++j) {
        index0 = i * src->widthStep + j;
        gray0 = src->imageData[index0];
        for (int k = -radius; k <= radius; ++k) {
          for (int l = -radius; l <= radius; ++l) {
            if ((i + k) >= 0 && (i + k) < src->height) {
              rowOffset = i + k;
            } else {
              rowOffset = 0;
            }
            if ((j + l) >= 0 && (j + l) < src->width) {
              colOffset = j + l;
            } else {
              colOffset = 0;
            }
            index = rowOffset * src->widthStep + colOffset;
            gray = src->imageData[index];
            weight = spaceWeightTable[k + radius][l + radius] * rangeWeightTable[abs(gray - gray0)];
            wSum += weight;
            sum += (weight * (double) gray);
          }
        }
        gray0 = (int) floor(sum / wSum);
        dst->imageData[index0] = clamp(gray0);
      }
    }
  }
  return 0;
}

int clamp(int p) {
  return p < 0 ? 0 : ((p > 255) ? 255 : p);
};




